﻿unit uNiuPlugin;

interface
uses
  WinApi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Spring.collections,
  uNiuGlobal, uNiuCommon;

type
  INiuServiceManager = interface(INiuServiceContainer)
    ['{C60CAF22-3AFE-4F29-BA87-050F7141E1BC}']

  end;

  TNiuBasePluginLoader = class(TObject)
  private
    FDllFilePath: string;
    FLibHandle: THandle;

    function LoadPlugin():Boolean;
    procedure UnloadPlugin();
  protected
    function DoBeforeLoad(const aDllFilePath: string): Boolean; virtual;
    function DoAfterLoad(const aDllFilePath: string; aLibHandle: THandle): Boolean; virtual;

    procedure DoBeforeUnLoad(const aDllFilePath: string; aLibHandle: THandle); virtual;
    procedure DoAfterUnLoad(const aDllFilePath: string); virtual;

  public
    constructor create(const aDllFilePath: String); virtual;
    destructor destroy; override;


    property DllFilePath: string read FDllFilePath;
    property LibHandle: THandle read FLibHandle;
  end;

type
  // 一个进程内，全局共享对象管理器，线程安全
  TNiuServiceManager = class(TNiuGlobalShareObject, INiuServiceManager, INiuGlobalShareObject)
  strict private
    class var _Instance : INiuServiceManager;
    class constructor Create;   //类构造函数‌（class constructor）的特性：在‌类首次被使用前自动调用‌只会执行一次，且线程安全
    class destructor Destroy;
  private
    FServiceContainer : INiuServiceContainer;
  protected
    //////////////////////////////////////////////////////////
    // 泛类型服务（不做接口类型检查）
    //////////////////////////////////////////////////////////
    // 注册单实例服务
    function RegisterService(const aNameSpace:PAnsiChar; const aService:IInterface; aOverrideExist:Boolean=False):Boolean;  overload;stdcall;
    procedure unRegisterService(const aNameSpace:PAnsiChar); overload;stdcall;
    function TryGetService(const aNameSpace:PAnsiChar; out aService:IInterface):Boolean;  overload;stdcall;

    // 注册单实例命名服务 - 别名
    function RegisterService(const aNameSpace:PAnsiChar; const aAlias:PAnsiChar; const aService:IInterface; aOverrideExist:Boolean=False):Boolean; overload;stdcall;
    procedure unRegisterService(const aNameSpace:PAnsiChar; const aAlias:PAnsiChar); overload;stdcall;
    function TryGetService(const aNameSpace:PAnsiChar; const aAlias:PAnsiChar; out aService:IInterface):Boolean; overload;stdcall;

    // 注册多实例无名服务
    function RegisterServices(const aNameSpace:PAnsiChar; const aServices:TArray<IInterface>; aOverrideExist:Boolean=False):Boolean;  overload;stdcall;
    procedure unRegisterServices(const aNameSpace:PAnsiChar; const aServices:TArray<IInterface>); overload;stdcall;
    function TryGetServices(const aNameSpace:PAnsiChar):IList<IInterface>;  overload;stdcall;

    //////////////////////////////////////////////////////////
    // 强类型服务（做接口类型检查）
    //////////////////////////////////////////////////////////
    // 注册单实例服务
    function RegisterService(const aGuid:TGuid; const aService:IInterface; aOverrideExist:Boolean=False):Boolean;  overload;stdcall;
    procedure unRegisterService(const aGuid:TGuid); overload;stdcall;
    function TryGetService(const aGuid:TGuid; out aService):Boolean;  overload;stdcall;

    // 注册单实例命名服务 - 别名
    function RegisterService(const aGuid:TGuid; const aAlias:PAnsiChar; const aService:IInterface; aOverrideExist:Boolean=False):Boolean; overload;stdcall;
    procedure unRegisterService(const aGuid:TGuid; const aAlias:PAnsiChar); overload;stdcall;
    function TryGetService(const aGuid:TGuid; const aAlias:PAnsiChar; out aService):Boolean; overload;stdcall;

    // 注册多实例无名服务
    function RegisterServices(const aGuid:TGuid; const aServices:TArray<IInterface>; aOverrideExist:Boolean=False):Boolean;  overload;stdcall;
    procedure unRegisterServices(const aGuid:TGuid; const aServices:TArray<IInterface>); overload;stdcall;
    function TryGetServices(const aGuid:TGuid):IList<IInterface>;  overload;stdcall;

    procedure Clear; stdcall;

  public
    class function GetInstance():INiuServiceManager;

    constructor Create; override;
    destructor Destroy; override;
  end;

implementation

{ TNiuServiceManager }
class constructor TNiuServiceManager.Create;
  function _CreateSericeManager():INiuServiceManager;
  begin
    with TShareWithinProcessManager.GetInstance() do begin
      if not TryGetService(INiuServiceManager, Result) then begin
         Result := TNiuServiceManager.Create();
         RegisterService(INiuServiceManager, Result);       // 注册到全局
      end;
    end;
  end;
begin
  _Instance := _CreateSericeManager();
end;

class destructor TNiuServiceManager.Destroy;
  procedure _DestroySericeManager(const aInstance:INiuServiceManager);
  begin
    var mCreateHandle := (aInstance as INiuGlobalShareObject).CreateHandle;
    if mCreateHandle <> HInstance then Exit;
    with TShareWithinProcessManager.GetInstance() do begin
       unRegisterService(INiuServiceManager);
    end;
  end;
begin
  if Assigned(_Instance) then
  try
     _DestroySericeManager(_Instance);
  finally
     _Instance := nil;
  end;
end;

class function TNiuServiceManager.GetInstance: INiuServiceManager;
begin
  Result := _Instance;
end;

constructor TNiuServiceManager.Create;
begin
  inherited;

  FServiceContainer := TNiuServiceContainer.Create;
end;


destructor TNiuServiceManager.destroy;
begin
  FServiceContainer.Clear;
  if Assigned(FServiceContainer) then FServiceContainer := nil;
  inherited;
end;

////// aNameSpace
function TNiuServiceManager.RegisterService(const aNameSpace:PAnsiChar; const aService: IInterface; aOverrideExist:Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterService(aNameSpace, aService, aOverrideExist);
end;

function TNiuServiceManager.RegisterService(const aNameSpace, aAlias: PAnsiChar; const aService: IInterface;
  aOverrideExist: Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterService(aNameSpace, aAlias, aService, aOverrideExist);
end;

function TNiuServiceManager.RegisterServices(const aNameSpace:PAnsiChar; const aServices:TArray<IInterface>; aOverrideExist:Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterServices(aNameSpace, aServices, aOverrideExist);
end;

procedure TNiuServiceManager.unRegisterService(const aNameSpace:PAnsiChar);
begin
  FServiceContainer.unRegisterService(aNameSpace);
end;

procedure TNiuServiceManager.unRegisterService(const aNameSpace, aAlias: PAnsiChar);
begin
  FServiceContainer.unRegisterService(aNameSpace, aAlias);
end;

procedure TNiuServiceManager.unRegisterServices(const aNameSpace:PAnsiChar;const aServices:TArray<IInterface>);
begin
  FServiceContainer.unRegisterServices(aNameSpace, aServices);
end;


function TNiuServiceManager.TryGetService(const aNameSpace:PAnsiChar; out aService: IInterface): boolean;
begin
  Result := FServiceContainer.TryGetService(aNameSpace, aService);
end;

function TNiuServiceManager.TryGetServices(const aNameSpace:PAnsiChar):IList<IInterface>;
begin
  Result := FServiceContainer.TryGetServices(aNameSpace);
end;

function TNiuServiceManager.TryGetService(const aNameSpace, aAlias: PAnsiChar;
  out aService: IInterface): Boolean;
begin
  Result := FServiceContainer.TryGetService(aNameSpace, aAlias, aService);
end;


//// TGUID
function TNiuServiceManager.RegisterService(const aGuid: TGUID; const aService: IInterface; aOverrideExist:Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterService(aGuid, aService, aOverrideExist);
end;

function TNiuServiceManager.RegisterService(const aGuid: TGUID; const aAlias:PAnsiChar; const aService: IInterface; aOverrideExist:Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterService(aGuid, aAlias, aService, aOverrideExist);
end;

function TNiuServiceManager.RegisterServices(const aGuid: TGuid; const aServices: TArray<IInterface>;
  aOverrideExist: Boolean): Boolean;
begin
  Result := FServiceContainer.RegisterServices(aGuid, aServices, aOverrideExist);
end;

procedure TNiuServiceManager.unRegisterService(const aGuid: TGUID);
begin
  FServiceContainer.unRegisterService(aGuid);
end;

procedure TNiuServiceManager.unRegisterService(const aGuid: TGUID; const aAlias:PAnsiChar);
begin
  FServiceContainer.unRegisterService(aGuid, aAlias);
end;

procedure TNiuServiceManager.unRegisterServices(const aGuid: TGuid; const aServices: TArray<IInterface>);
begin
  FServiceContainer.unRegisterServices(aGuid, aServices);
end;

function TNiuServiceManager.TryGetService(const aGuid: TGUID; out aService): boolean;
begin
  Result := FServiceContainer.TryGetService(aGuid, aService);
end;

function TNiuServiceManager.TryGetService(const aGuid: TGUID; const aAlias:PAnsiChar; out aService): boolean;
begin
  Result := FServiceContainer.TryGetService(aGuid, aAlias, aService);
end;

function TNiuServiceManager.TryGetServices(const aGuid: TGUID):IList<IInterface>;
begin
  Result := FServiceContainer.TryGetServices(aGuid);
end;


procedure TNiuServiceManager.Clear;
begin
  FServiceContainer.Clear();
end;

{ TNiuBasePluginLoader }

constructor TNiuBasePluginLoader.create(const aDllFilePath: String);
begin
  inherited create;

  FDllFilePath := aDllFilePath;
  FLibHandle   := 0;
  if not LoadPlugin() then begin
     raise Exception.CreateFmt('插件加载失败：%s',[aDllFilePath]);
  end;
end;

destructor TNiuBasePluginLoader.destroy;
begin
  unLoadPlugin();
  inherited;
end;

function TNiuBasePluginLoader.LoadPlugin():Boolean;
begin
  Result := False;

  if not FileExists(FDllFilePath) then begin
     raise Exception.CreateFmt('文件不存在：%s', [FDllFilePath]);  // Exit;
  end;

  if DoBeforeLoad(FDllFilePath) then
  begin
      FLibHandle := LoadLibrary(PChar(FDllFilePath));   //

      if FLibHandle = 0 then begin
         raise Exception.CreateFmt('插件加载失败：%s', [FDllFilePath]);  // Exit;
      end;

      if not DoAfterLoad(FDllFilePath, FLibHandle) then begin
         UnloadPlugin();
         Exit;
      end;

      Result := True;
  end;
end;

procedure TNiuBasePluginLoader.UnloadPlugin();
begin
  if FLibHandle = 0 then Exit;

  try
    DoBeforeUnLoad(FDllFilePath, FLibHandle);
  finally
    try
      FreeLibrary(FLibHandle);
    finally
      FLibHandle := 0;
    end;
    DoAfterUnLoad(FDllFilePath);
  end;
end;

function TNiuBasePluginLoader.DoBeforeLoad(const aDllFilePath: string): Boolean;
begin
  Result := True;
end;

function TNiuBasePluginLoader.DoAfterLoad(const aDllFilePath: string; aLibHandle: THandle): Boolean;
begin
  Result := True;
end;

procedure TNiuBasePluginLoader.DoBeforeUnLoad(const aDllFilePath: string; aLibHandle: THandle);
begin

end;

procedure TNiuBasePluginLoader.DoAfterUnLoad(const aDllFilePath: string);
begin

end;

initialization

finalization

end.
